/**
 * Jynx
 * 
 * The Java-based Lynx clone.
 * -----------------------------------------------------------------------------
 * Programmer:     Jonathan Landrum
 * Program:        jynx.java
 * Date:           23 February 2013
 * Purpose:        This program attempts to be a text-based browser in the
 *                 fashion of Lynx. It is so named because it is "Jon's Lynx",
 *                 or alternatively, "Java Lynx".
 * Dependencies:   java.io.*
 *                 java.net.*
 *                 java.util.*
 * Changelog:
 * -----------------------------------------------------------------------------
 * Date:        Programmer:    Version:    Description:
 * -----------------------------------------------------------------------------
 * 25 Jul 14    jonlandrum     1.0         Cleaned up output, solved redirects
 * 22 Jul 14    jonlandrum     0.1.1       Moved to GitHub
 * 23 Feb 13    jonlandrum     0.1         Initial release  
 * -----------------------------------------------------------------------------
 */

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;

public class jynx {
    public static void main (String[] args) throws IOException {
        // Create a scanner object and input variable
        String input = "";
        Scanner scan = new Scanner(System.in);
        
        // Open the containing frame
        //javax.swing.SwingUtilities.invokeLater(new Runnable() {
	  //public void run() {
	    //createAndShowGUI();
	  //}
        //});
        
        // Grab a URL from the user
        System.out.println ("Jynx, the Java-based Lynx clone.");
        System.out.print ("Address: ");
        input = scan.nextLine();
                
        // Attempt a connection with an initial redirect count of 0
        open(input, 0);
    }
    
    public static void open (String input, int limit) throws IOException {
        String output = "", host = "", port = "", directory = "";
        int portNum = 80, redirectLimit = limit;
        Socket socket = null;
        PrintWriter out = null;
        BufferedReader in = null;
        
        // Assume http(s); don't want to go down the gopher road
        if ((input.length() > 7) && (input.substring(0, 7).equals("http://"))) {
            input = input.substring(7);
        } else if ((input.length() > 8) && (input.substring(0, 8).equals("https://"))) {
            input = input.substring(8);
            portNum = 443;
        }
        
        // Grab the host and directory
        for (int c = 0; c < input.length(); ++c) {
            if (input.charAt(c) == '/') {
                host = input.substring(0, c);
                directory = input.substring(c);
                break;
            }
        }
        
        // Ensure we have a host and a directory (happens when no file or directory are specified in the request)
        if (host.equals("")) {
            host = input;
            directory = "/";
        }
        
        // Check for a specified port
        for (int c = 0; c < host.length(); ++c) {
            if (host.charAt(c) == ':') {
                for (int i = c + 1; i < host.length(); ++i)
                    port += host.charAt(i);
                portNum = Integer.parseInt(port);
                host = host.substring(0, c);
                break;
            }
        }

        try {
            // Set up the socket
            socket = new Socket (host, portNum);
            out = new PrintWriter (socket.getOutputStream());
            in = new BufferedReader (new InputStreamReader (socket.getInputStream()));
            
            // Send the request and get the response
            out.print("GET " + directory + " HTTP/1.1\r\n");
            out.print("Host: " + host + "\r\n");
            out.print("\r\n");
            out.flush();
            
            // Check for 301 or 302 redirects
            while (!(output = in.readLine()).toLowerCase().contains("<body")) {
                if ((output.toLowerCase().contains("301 moved permanently")) ||
                    (output.toLowerCase().contains("302 found"))) {
                    while (!(output = in.readLine()).toLowerCase().startsWith("location: "));
                    host = output.substring(10);
                    
                    // Close all connections
                    in.close();
                    out.close();
                    socket.close();
                    
                    // Start a new connection
                    if (redirectLimit < 10) {
                        open(host, ++redirectLimit);
                    } else {
                        System.out.println ("Error: Too many redirects.");
                    }
                }
            }
            
            // Print the body text (assume we're hitting a site with valid html)
            while (!(output = in.readLine()).toLowerCase().contains("</body")) {
                System.out.println (output);
            }
        } catch (Exception e) {
	    // Handle any exceptions
            System.err.println (e);
            System.exit(1);
        } finally {
            // Close all connections
            in.close();
            out.close();
            socket.close();
            System.exit(0);
        }
    }
    
    private static void createAndShowGUI() {
      //JFrame.setDefaultLookAndFeelDecorated(true);
      JFrame frame = new JFrame("Jynx");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      
      JLabel emptyLabel = new JLabel("");
      emptyLabel.setPreferredSize(new Dimension(800, 600));
      frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
      
      frame.pack();
      frame.setVisible(true);
    }
}
